Простые приложения на Java
Простые приложения на Java
Java представляет собой объектно-ориентированный язык программирования, который широко используется для создания настольных приложений, серверных систем и мобильных решений. Язык отличается строгой типизацией, автоматическим управлением памятью (Garbage Collection) и кроссплатформенностью благодаря виртуальной машине Java (JVM).
В данной главе рассматриваются практические примеры простых консольных приложений. Каждый пример демонстрирует ключевые концепции языка: работу со строками, массивами, коллекциями, файловым вводом-выводом, сетевым взаимодействием и многопоточностью.
Генератор случайных паролей
Это приложение демонстрирует работу с классом String, массивами символов, интерфейсом Random и циклами. Код создает пароль заданной длины, выбирая символы из набора букв, цифр и специальных знаков.
Разбор кода
- Массивы: Хранение допустимых символов.
- Random: Генерация индексов для выбора случайного символа.
- StringBuilder: Эффективное построение итоговой строки без создания множества временных объектов.
import java.util.Random;
public class PasswordGenerator {
public static void main(String[] args) {
int length = 12;
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
StringBuilder password = new StringBuilder();
Random random = new Random();
for (int i = 0; i < length; i++) {
int index = random.nextInt(chars.length());
char ch = chars.charAt(index);
password.append(ch);
}
System.out.println("Сгенерированный пароль: " + password.toString());
}
}
Ключевые моменты:
- Использование
StringBuilderвместо конкатенации строк в цикле повышает производительность. - Метод
nextInt(int bound)возвращает случайное целое число от 0 (включительно) до указанного значения (исключительно).
Сортировщик текстового файла
Приложение читает текст из файла, разбивает его на слова, сортирует их по алфавиту и записывает результат в новый файл. Это пример работы с потоками ввода-вывода (InputStreamReader, BufferedReader) и коллекциями (ArrayList, Collections).
Разбор кода
- NIO и IO: Классы
Files,Paths,FileReaderдля чтения данных. - Коллекции: Список
ArrayListдля хранения слов. - Сортировка: Алгоритм
Collections.sort().
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.Collectors;
public class TextSorter {
public static void main(String[] args) {
Path inputPath = Paths.get("input.txt");
Path outputPath = Paths.get("output_sorted.txt");
try {
// Чтение всего содержимого файла
String content = Files.readString(inputPath);
// Разбиение на слова (по пробелам и знакам препинания)
List<String> words = Arrays.stream(content.split("\\s+"))
.filter(word -> !word.isEmpty())
.collect(Collectors.toList());
// Сортировка списка
Collections.sort(words);
// Запись результата
String sortedContent = String.join("\n", words);
Files.writeString(outputPath, sortedContent);
System.out.println("Файл успешно отсортирован. Количество слов: " + words.size());
} catch (IOException e) {
System.err.println("Ошибка при работе с файлом: " + e.getMessage());
}
}
}
Ключевые моменты:
- Метод
Files.readString(доступен в Java 11+) упрощает чтение файлов. - Регулярное выражение
\\s+позволяет корректно разделить текст по любому количеству пробельных символов. - Обработка исключений через блок
try-catchгарантирует безопасность программы при отсутствии файла.
Консольный калькулятор
Простой интерактивный калькулятор, выполняющий арифметические операции (+, -, *, /). Пример демонстрирует работу с пользовательским вводом (Scanner), условными операторами и обработкой ошибок деления на ноль.
Разбор кода
- Scanner: Получение данных от пользователя.
- Условная логика: Оператор
switchдля выбора операции. - Типы данных: Переход от
Stringкdoubleдля вычислений.
import java.util.Scanner;
public class ConsoleCalculator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean running = true;
while (running) {
System.out.print("Введите первое число (или 'q' для выхода): ");
String input1 = scanner.nextLine();
if (input1.equalsIgnoreCase("q")) {
break;
}
double num1 = Double.parseDouble(input1);
System.out.print("Выберите операцию (+, -, *, /): ");
String operation = scanner.nextLine();
System.out.print("Введите второе число: ");
double num2 = Double.parseDouble(scanner.nextLine());
double result = 0;
boolean validOperation = true;
switch (operation) {
case "+":
result = num1 + num2;
break;
case "-":
result = num1 - num2;
break;
case "*":
result = num1 * num2;
break;
case "/":
if (num2 == 0) {
System.out.println("Ошибка: Деление на ноль!");
validOperation = false;
} else {
result = num1 / num2;
}
break;
default:
System.out.println("Неверная операция.");
validOperation = false;
}
if (validOperation) {
System.out.printf("Результат: %.2f%n", result);
}
}
System.out.println("Программа завершена.");
scanner.close();
}
}
Характерная черта Java: Строгая проверка типов. Попытка сложить строку и число вызовет ошибку компиляции, что предотвращает многие типы runtime-ошибок.
Трекер задач в JSON
Приложение сохраняет список задач в файл формата JSON и загружает его обратно. Для работы с JSON используется библиотека org.json или встроенные возможности, но в примере ниже показана реализация на основе простого сериализатора вручную или с использованием стандартной библиотеки Jackson (предполагается наличие зависимости). Для автономности примера будет использован простой формат, имитирующий JSON, либо структура класса.
Примечание: В реальных проектах используют Jackson или Gson. Здесь представлен пример с ручным парсингом для демонстрации логики.
Разбор кода
- POJO (Plain Old Java Object): Класс
Taskдля представления задачи. - Файловая система: Создание директорий и запись/чтение файлов.
- JSON-структура: Представление данных в виде строковой формы.
import java.io.*;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
class Task {
private int id;
private String description;
private boolean completed;
public Task(int id, String description) {
this.id = id;
this.description = description;
this.completed = false;
}
@Override
public String toString() {
return "{\"id\":" + id + ",\"description\":\"" + description + "\",\"completed\":" + completed + "}";
}
// Упрощенный метод для создания объекта из строки (для примера)
public static Task fromJson(String jsonStr) {
// В реальном проекте используйте JsonParser
return null;
}
}
public class TaskTracker {
private static final String FILE_PATH = "tasks.json";
private List<Task> tasks = new ArrayList<>();
public void loadTasks() {
Path path = Paths.get(FILE_PATH);
if (Files.exists(path)) {
try {
String content = Files.readString(path);
// Здесь должна быть логика парсинга JSON строки в объекты Task
System.out.println("Задачи загружены (демо режим).");
} catch (IOException e) {
System.err.println("Ошибка чтения: " + e.getMessage());
}
}
}
public void saveTasks() {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < tasks.size(); i++) {
sb.append(tasks.get(i).toString());
if (i < tasks.size() - 1) sb.append(",");
}
sb.append("]");
try {
Files.writeString(Paths.get(FILE_PATH), sb.toString());
System.out.println("Задачи сохранены.");
} catch (IOException e) {
System.err.println("Ошибка записи: " + e.getMessage());
}
}
public void addTask(String desc) {
int id = tasks.size() > 0 ? tasks.get(tasks.size() - 1).getId() + 1 : 1;
tasks.add(new Task(id, desc));
}
public static void main(String[] args) {
TaskTracker tracker = new TaskTracker();
tracker.loadTasks();
tracker.addTask("Купить продукты");
tracker.addTask("Изучить Java");
tracker.saveTasks();
}
}
Рекомендация: Для продакшн-кода обязательно используйте библиотеку Jackson Databind или Gson. Они берут на себя всю сложность сериализации и десериализации.
Простой HTTP-сервер и клиент
Java предоставляет возможности для создания сетевых приложений через пакет java.net. Ниже приведен пример минимального сервера, слушающего порт, и клиента, отправляющего запрос.
Разбор кода
- ServerSocket: Объект для прослушивания входящих соединений.
- Socket: Объект для установления соединения.
- Потоки ввода/вывода:
InputStream,OutputStreamдля передачи данных.
// --- Сервер ---
import java.io.*;
import java.net.*;
public class SimpleHttpServer {
public static void main(String[] args) throws IOException {
int port = 8080;
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Сервер запущен на порту " + port);
while (true) {
Socket clientSocket = serverSocket.accept();
handleClient(clientSocket);
}
}
private static void handleClient(Socket socket) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
String requestLine = in.readLine();
System.out.println("Запрос: " + requestLine);
String response = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/plain\r\n" +
"\r\n" +
"Hello from Java Server!";
out.println(response);
socket.close();
}
}
// --- Клиент ---
import java.io.*;
import java.net.*;
public class HttpClient {
public static void main(String[] args) throws IOException {
URL url = new URL("http://localhost:8080");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int status = connection.getResponseCode();
System.out.println("Статус ответа: " + status);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Ответ сервера: " + response.toString());
}
}
Характерная черта Java: Встроенная поддержка TCP/IP на низком уровне. Не требуется подключение внешних драйверов для базовой сетевой коммуникации.
Отправитель HTTP-запросов (REST API)
Этот пример расширяет функциональность клиента, позволяя отправлять POST-запросы с данными в формате JSON. Используется HttpURLConnection для настройки заголовков и отправки тела запроса.
import java.io.*;
import java.net.*;
public class RestApiClient {
public static void main(String[] args) throws IOException {
String apiUrl = "https://jsonplaceholder.typicode.com/posts";
String jsonInput = "{ \"title\": \"foo\", \"body\": \"bar\", \"userId\": 1 }";
URL url = new URL(apiUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
try (OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInput.getBytes("utf-8");
os.write(input, 0, input.length);
}
int responseCode = conn.getResponseCode();
System.out.println("Отправлен запрос. Код ответа: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_CREATED) {
System.out.println("Ресурс успешно создан.");
}
conn.disconnect();
}
}
Утилита для сканирования директорий
Приложение обходит структуру папок и выводит список всех файлов с указанием их размера и пути. Используется рекурсивный обход или класс Files.walk.
Разбор кода
- Files.walk: Поток путей, представляющий дерево директорий.
- Фильтрация: Исключение скрытых файлов или определенных расширений.
import java.io.IOException;
import java.nio.file.*;
import java.util.stream.Stream;
public class DirectoryScanner {
public static void main(String[] args) {
Path startPath = Paths.get("."); // Текущая директория
try (Stream<Path> stream = Files.walk(startPath)) {
stream
.filter(Files::isRegularFile) // Только файлы
.forEach(path -> {
long size = 0;
try {
size = Files.size(path);
} catch (IOException e) {
// Игнорирование ошибок доступа
}
System.out.printf("%s (%d байт)%n", path, size);
});
} catch (IOException e) {
System.err.println("Ошибка сканирования: " + e.getMessage());
}
}
}
Скрипт для создания резервного копирования файлов
Приложение копирует файлы из одной директории в другую с добавлением временной метки к имени файла. Это демонстрирует работу с StandardCopyOption и манипуляцию именами файлов.
import java.io.IOException;
import java.nio.file.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class BackupUtility {
public static void main(String[] args) {
Path sourceDir = Paths.get("source_data");
Path backupDir = Paths.get("backup_data");
try {
// Создание директории бэкапа, если её нет
Files.createDirectories(backupDir);
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
String timestamp = now.format(formatter);
// Поиск всех файлов в источнике
try (var stream = Files.list(sourceDir)) {
stream.forEach(file -> {
try {
String fileName = file.getFileName().toString();
String nameWithoutExt = fileName.substring(0, fileName.lastIndexOf('.'));
String ext = fileName.substring(fileName.lastIndexOf('.'));
Path newPath = backupDir.resolve(nameWithoutExt + "_" + timestamp + ext);
Files.copy(file, newPath, StandardCopyOption.REPLACE_EXISTING);
System.out.println("Скопировано: " + fileName + " -> " + newPath.getFileName());
} catch (Exception e) {
System.err.println("Ошибка копирования " + file + ": " + e.getMessage());
}
});
}
} catch (IOException e) {
System.err.println("Критическая ошибка: " + e.getMessage());
}
}
}
Мониторинг дискового пространства
Утилита отображает информацию о свободном и занятом месте на диске. Используется класс FileStore из пакета java.nio.file.
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
public class DiskSpaceMonitor {
public static void main(String[] args) {
File root = new File("/"); // Корневая директория
try {
FileStore store = FileSystems.getDefault().getFileStore(root.toPath());
long totalSize = store.getTotalSpace();
long usableSize = store.getUsableSpace();
long usedSize = totalSize - usableSize;
System.out.println("Диск: " + root.getAbsolutePath());
System.out.println("Общий размер: " + formatBytes(totalSize));
System.out.println("Занято: " + formatBytes(usedSize));
System.out.println("Свободно: " + formatBytes(usableSize));
System.out.println("Процент использования: " + (totalSize > 0 ? (usedSize * 100 / totalSize) : 0) + "%");
} catch (IOException e) {
System.err.println("Ошибка получения информации о диске: " + e.getMessage());
}
}
private static String formatBytes(long bytes) {
if (bytes < 1024) return bytes + " B";
if (bytes < 1024 * 1024) return bytes / 1024 + " KB";
if (bytes < 1024 * 1024 * 1024) return bytes / (1024 * 1024) + " MB";
return bytes / (1024L * 1024 * 1024) + " GB";
}
}
Парсер URL и проверка доступности ресурса
Приложение принимает URL, разбирает его компоненты (протокол, хост, путь) и проверяет, доступен ли ресурс по HTTP.
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
public class UrlChecker {
public static void main(String[] args) {
String urlString = "https://example.com";
try {
URL url = new URL(urlString);
System.out.println("Анализ URL: " + urlString);
System.out.println("Протокол: " + url.getProtocol());
System.out.println("Хост: " + url.getHost());
System.out.println("Порт: " + url.getPort());
System.out.println("Путь: " + url.getPath());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD"); // HEAD запрос быстрее GET
connection.setConnectTimeout(5000); // 5 секунд таймаут
connection.connect();
int statusCode = connection.getResponseCode();
System.out.println("Статус кода: " + statusCode);
if (statusCode >= 200 && statusCode < 300) {
System.out.println("Ресурс доступен.");
} else {
System.out.println("Ресурс недоступен или вернул ошибку.");
}
connection.disconnect();
} catch (UnknownHostException e) {
System.out.println("Ошибка: Хост не найден.");
} catch (IOException e) {
System.out.println("Ошибка сети: " + e.getMessage());
}
}
}
Конвертер форматов дат
Работа с датами в Java требует внимания к деталям. Приведен пример конвертации между старым форматом SimpleDateFormat (для совместимости) и новым API java.time (рекомендуемый стандарт с Java 8).
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
public class DateConverter {
public static void main(String[] args) {
String dateString = "2026-05-06 14:30:00";
String inputPattern = "yyyy-MM-dd HH:mm:ss";
String outputPattern = "dd/MM/yyyy HH:mm";
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputPattern);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputPattern);
try {
LocalDateTime dateTime = LocalDateTime.parse(dateString, inputFormatter);
// Конвертация в другой формат
String formattedDate = dateTime.format(outputFormatter);
System.out.println("Исходная строка: " + dateString);
System.out.println("Преобразованная строка: " + formattedDate);
// Пример получения даты сегодня
LocalDate today = LocalDate.now();
System.out.println("Сегодня: " + today);
} catch (DateTimeParseException e) {
System.out.println("Неверный формат даты: " + e.getMessage());
}
}
}
Утилита для просмотра запущенных процессов
Приложение выводит список активных процессов операционной системы с их идентификаторами (PID) и названиями. В Java для этого используется класс ProcessHandle.
import java.util.Comparator;
import java.util.stream.Stream;
public class ProcessViewer {
public static void main(String[] args) {
System.out.println("Список запущенных процессов:");
System.out.println("PID\t\tName");
System.out.println("---------------------------");
// Stream API для обработки процесса
try (Stream<ProcessHandle> processes = ProcessHandle.allProcesses()) {
processes
.sorted(Comparator.comparingLong(ProcessHandle::pid))
.forEach(process -> {
long pid = process.pid();
String name = process.info().command().orElse("N/A");
// Ограничение вывода первых 100 символов имени
if (name.length() > 100) {
name = name.substring(0, 97) + "...";
}
System.out.printf("%d\t%s%n", pid, name);
});
}
}
}
Характерная черта Java: Класс ProcessHandle предоставляет безопасный и удобный способ взаимодействия с процессами ОС без необходимости вызова нативных библиотек.